package com.baseweb.webadmin.extshiro.realm;

import com.baseweb.webadmin.core.constants.LoginType;
import com.baseweb.webadmin.core.constants.UserType;
import com.baseweb.webadmin.core.model.pojo.Resc;
import com.baseweb.webadmin.core.model.pojo.Role;
import com.baseweb.webadmin.core.model.pojo.User;
import com.baseweb.webadmin.core.model.pojo.UserRoleKey;
import com.baseweb.webadmin.core.util.MD5Util;
import com.baseweb.webadmin.extshiro.ZheUsernamePasswordToken;
import com.baseweb.webadmin.service.RoleRescService;
import com.baseweb.webadmin.service.RoleService;
import com.baseweb.webadmin.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;

/**
 * Created by IntelliJ IDEA.
 * User: baseweb
 * Date: 11-4-8
 * Time: 下午12:13
 * 根据googleAd项目的实际情况 取得
 */
public class JobManageJdbcRealm extends JdbcRealm {

    private static final Logger log = LoggerFactory.getLogger(JobManageJdbcRealm.class);

    @Autowired
    private RoleService roleService;

    @Autowired
    private UserService userService;

    @Autowired
    private RoleRescService roleRescService;

    @Value("#{commonProps['ldap.url']}")
    private String ldapUrl;

    @Value("#{commonProps['ldap.search']}")
    private String search;

    @Value("#{commonProps['ldap.default.user']}")
    private String defaultUserName;

    @Value("#{commonProps['ldap.default.password']}")
    private String defaultPassword;

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        ZheUsernamePasswordToken upToken = (ZheUsernamePasswordToken) token;
        String username = upToken.getUsername();
        if (username == null) {
            throw new AccountException("Null usernames are not allowed by this realm.");
        }

        String password;
        if (upToken.getUserType() != null && upToken.getUserType().equals(LoginType.WEIXIN.getCode())) {
            password = MD5Util.Md5(String.valueOf(upToken.getPassword()));
        }else {
            password = getDbPassword(username);
        }
//        } else {
//            password = getPassWordByLdap(upToken);
//        }

        if (password == null) {
            throw new UnknownAccountException("No account found for user [" + username + "]");
        }

        return new SimpleAuthenticationInfo(username, password.toCharArray(), getName());
    }

    protected AuthenticationInfo buildAuthenticationInfo(String username, char[] password) {
        return new SimpleAuthenticationInfo(username, password, getName());
    }

    public String getPassWordByLdap(AuthenticationToken token) {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String password = new String(upToken.getPassword());
        String userName = upToken.getUsername();

        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, ldapUrl + "dc=baseweb-inc,dc=com");
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        SearchResult result = getUserDN(userName);
        if (result == null) {
            return null;
        }
        env.put(Context.SECURITY_PRINCIPAL, result.getName() + ",dc=baseweb-inc,dc=com");
        env.put(Context.SECURITY_CREDENTIALS, password);
        DirContext ctx = null;

        try {
            ctx = new InitialDirContext(env);
            log.info("认证成功:" + result.getName());

            User user = userService.selectByName(userName);
            if (user == null) {//用户第一次登陆系统 新建用户
                user = new User();
                Attributes attrs = result.getAttributes();
                user.setUsername(attrs.get("uid").get().toString());
//                user.setPassword("e10adc3949ba59abbe56e057f20f883e");//密码没什么用处了
                user.setEmail(attrs.get("mail").get().toString());
                user.setStatus(1);
//                user.setUserType(UserType.LDAP.getTypeValue());
                user.setDescn(attrs.get("displayname").get().toString() + "-" + attrs.get("location").get().toString());
                int r = userService.insertUser(user);
                if (r > 0) {
                    UserRoleKey key = new UserRoleKey();
                    key.setUserId(user.getId());
                    key.setRoleId(7);
                    roleService.insertUserRoleKey(key);
                }
            }
            return MD5Util.Md5(password.trim());
        } catch (javax.naming.AuthenticationException e) {
            e.printStackTrace();
            log.info("认证失败:" + result.getName());
        } catch (Exception e) {
            e.printStackTrace();
            log.info("认证出错:" + result.getName());
        } finally {
            if (ctx != null) {
                try {
                    ctx.close();
                } catch (NamingException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    private SearchResult getUserDN(String uid) {
        String userName = defaultUserName;
        String password = defaultPassword;

        String root = "dc=baseweb-inc,dc=com";
        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, ldapUrl + root);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, "cn=" + userName + ",dc=baseweb-inc,dc=com");
        env.put(Context.SECURITY_CREDENTIALS, password);
        DirContext ctx = null;

        try {
            ctx = new InitialDirContext(env);

            SearchControls sc = new SearchControls();
            sc.setSearchScope(SearchControls.SUBTREE_SCOPE);

            String s = String.format(search, uid);
            NamingEnumeration<SearchResult> enumeration = ctx.search("", s, sc);
            if (enumeration.hasMoreElements()) {
                return enumeration.next();
            }
        } catch (javax.naming.AuthenticationException e) {
            e.printStackTrace();
            log.info("getUserDN 失败");
        } catch (Exception e) {
            log.info("getUserDN 出错：");
            e.printStackTrace();
        } finally {
            if (ctx != null) {
                try {
                    ctx.close();
                } catch (NamingException e) {
                    e.printStackTrace();
                }
            }
        }

        return null;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }

        String username = (String) getAvailablePrincipal(principals);
        User user = userService.selectByName(username);
//        User user = (User) getAvailablePrincipal(principals);

        Set<String> permissions = new HashSet<String>();
        Set<String> roleNames = new HashSet<String>();
        if (user != null) {
            List<Role> roleList = roleService.selectRoleListByUser(user.getId().toString());
            for (Role r : roleList) {
                roleNames.add(r.getId().toString());
                if (permissionsLookupEnabled) {
                    List<Resc> rescList = roleRescService.getRescByRole(r.getId());
                    for (Resc resc : rescList) {
                        permissions.add(resc.getResString());
                    }
                }
            }
        }

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
        info.setStringPermissions(permissions);
        return info;
    }

    private String getDbPassword(String userName) {
        User user = userService.selectByName(userName);
        if (user != null) {
            return user.getPassword();
        } else {
            return null;
        }
    }
}
